package org.onion.pattern.event.spring.listener;

import jakarta.annotation.PostConstruct;
import lombok.extern.slf4j.Slf4j;
import org.onion.pattern.event.domain.Event;
import org.onion.pattern.event.spring.outbox.OutboxEventHandler;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.event.EventListener;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.stereotype.Component;

import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 外部化的监听
 */
@Component
@Slf4j
public class SpringEventHandlerMatchListener implements ApplicationContextAware {

    private ApplicationContext         applicationContext;
    private List<EventListenerHandler> eventListenerHandlers;
    @Autowired(required = false)
    private OutboxEventHandler outboxEventHandler;

    @PostConstruct
    protected void init() {
        Map<String, EventListenerHandler> beansOfType = this.applicationContext.getBeansOfType(EventListenerHandler.class);
        if (beansOfType.isEmpty()) {
            throw new IllegalStateException("【事件监听器】没有找到任何的 EventHandler 实现类");
        }
        //todo 超小越高（降序） , 加上是否独占
        eventListenerHandlers = beansOfType.values().stream().sorted(Comparator.comparing(EventListenerHandler::getOrder)).collect(Collectors.toList());
    }

    public boolean supportsEventType(Object event) {
        if (event instanceof Event) {
            return true;
        }
        org.onion.pattern.event.domain.annotation.Event annotation = AnnotationUtils.findAnnotation(event.getClass(),
                org.onion.pattern.event.domain.annotation.Event.class);
        if (annotation != null) {
            return true;
        }
        return false;
    }

    @EventListener
    public void on(Object event) {
        if (supportsEventType(event)) {
            handle(event);
        }
    }


    private void handle(Object event) {
        //todo 事务 处理 ??
        //todo 同步处理 ， 异常处理？？
        //todo 同时发送， 成功率 ？？
        log.debug("【事件】监听到事件 {}", event);

        if (this.outboxEventHandler != null) {
            if (this.outboxEventHandler.support(event)) {
                this.outboxEventHandler.handle(event);
                return;
            }
        }

        boolean nomatch = true;
        for (EventListenerHandler eventListenerHandler : eventListenerHandlers) {
            if (!eventListenerHandler.support(event)) {
                continue;
            }
            nomatch = false;
            eventListenerHandler.handle(event);
            if (eventListenerHandler.exclusive()) {
                break;
            }
        }

        if (nomatch) {
            log.warn("【事件】未配送到任务处理器事件 {}", event);
        }

    }


    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

}
